#include "echo_server.h"
#include "../log.h"

#include <string.h>

//监听客户端的读和写事件
void Session::Start()
{
    memset(m_data.get(), 0, m_max_length);
    m_socket.async_read_some(boost::asio::buffer(m_data.get(), m_max_length),
        [this](const boost::system::error_code& ec, size_t bytes){
            _handle_read_err(ec, bytes);
        });
}

//读事件回调
void Session::_handle_read_err(const boost::system::error_code& ec, size_t bytes)
{
    if(!ec)
    {
        log_info("server receive data:{}", m_data.get());
        boost::asio::async_write(m_socket, boost::asio::buffer(m_data.get(), bytes),
            std::bind(&Session::_handle_write_err, this, std::placeholders::_1));
        // boost::asio::async_write(m_socket, boost::asio::buffer(m_data.get(), bytes),
        //     [this](const boost::system::error_code& ec){
        //         _handle_write(ec);
        //     });
    }
    else 
    {
        log_error("read error, error code:{}, error msg:{}", ec.value(), ec.message());
        //这样删除指针可能会导致程序崩溃
        //如果写事件添加成功，但是数据还没有发送，这时客户端程序关闭连接，服务器会收到客户端的关闭事件，删除Session对象
        //这时，写事件回调函数会执行，也会删除Session对象会导致程序崩溃
        delete this;
    }
}

//写事件回调
void Session::_handle_write_err(const boost::system::error_code& ec)
{
    if(!ec)
    {
        memset(m_data.get(), 0, m_max_length);
        m_socket.async_read_some(boost::asio::buffer(m_data.get(), m_max_length),
            [this](const boost::system::error_code& ec, size_t bytes){
                _handle_read_err(ec, bytes);
            });
    }   
    else
    {
       log_error("write error, error code:{}, error msg:{}", ec.value(), ec.message());
       delete this;
    }
}


void Session::NewStart()
{
    memset(m_data.get(), 0, m_max_length);
    m_socket.async_read_some(boost::asio::buffer(m_data.get(), m_max_length),
        [this, ptr = shared_from_this()](const boost::system::error_code& ec, size_t bytes){
            _handle_read(ec, bytes, ptr);
        });
}

void Session::_handle_read(const boost::system::error_code& ec, size_t bytes, std::shared_ptr<Session> self_ptr)
{
    if(!ec)
    {
        log_info("server receive data:{}", m_data.get());
        m_socket.async_send(boost::asio::buffer(m_data.get(), bytes),
            std::bind(&Session::_handle_write, this, std::placeholders::_1, shared_from_this()));
    }
    else 
    {
        log_error("read error, error code:{}, error msg:{}", ec.value(), ec.message());
        m_server->DeleteSession(self_ptr->GetUUID());
    }
}

void Session::_handle_write(const boost::system::error_code& ec, std::shared_ptr<Session> self_ptr)
{
    if(!ec)
    {
        memset(m_data.get(), 0, m_max_length);
        m_socket.async_read_some(boost::asio::buffer(m_data.get(), m_max_length),
            [this, ptr = shared_from_this()](const boost::system::error_code& ec, size_t bytes){
                _handle_read(ec, bytes, ptr);
            });
    }
    else
    {
        log_error("write error, error code:{}, error msg:{}", ec.value(), ec.message());
        m_server->DeleteSession(self_ptr->GetUUID());
    }
}


//============================================================================================

Server::Server(boost::asio::io_context& ioc, uint16_t port)
:m_ioc(ioc)
,m_acceptor(ioc, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
{
    // _start_accetp_err();
    _start_accetp();
    log_debug("server start listen on port:{}", port);
}

//监听客户端的连接
void Server::_start_accetp_err()
{
    Session* session = new Session(m_ioc);
    // m_acceptor.async_accept(session->Socket(),
    //     std::bind(&Server::_handle_accept, this, session, std::placeholders::_1));
    m_acceptor.async_accept(session->Socket(),
        [this, session](const boost::system::error_code& ec){
            _handle_accept_err(session, ec);
        });
}

//链接回调
void Server::_handle_accept_err(Session* session, const boost::system::error_code& ec)
{
    if(!ec)
    {
        session->Start();
    }
    else 
    {
        log_error("accept error, error code:{}, error msg:{}", ec.value(), ec.message());
        delete session;
    }
    _start_accetp_err();
}


void Server::_start_accetp()
{
    std::shared_ptr<Session> session = std::make_shared<Session>(m_ioc, this);
    m_acceptor.async_accept(session->Socket(), 
    [this, session](const boost::system::error_code& ec){
        _handle_accept(session, ec);
    });
}

void Server::_handle_accept(std::shared_ptr<Session> session, const boost::system::error_code& ec)
{
    if(!ec)
    {
        m_sessions.insert(std::make_pair(session->GetUUID(), session));
        session->NewStart();
    }
    else
    {
        log_error("accept error, error code:{}, error msg:{}", ec.value(), ec.message());
    }
    _start_accetp();
}

void Server::DeleteSession(const std::string& uuid)
{
    auto find = m_sessions.find(uuid);
    if(find == m_sessions.end())
    {
        log_debug("session not found, uuid:{}", uuid);
        return;
    }
    m_sessions.erase(find);
}